package c2.group.business.teampvp;


import c2.advanced.business.base.KvData;
import c2.group.business.GroupBody;
import c2.group.business.base.GroupModule;
import c2.group.business.base.GroupSubModule;
import c2.group.business.teampvp.sub.*;
import cate.common.util.GameResult;
import cate.game.play.part.PlaySide;
import cate.game.pvp.teampvp.TeamPvpReport;
import cate.game.pvp.teampvp.dto.TeamPvpMatchData;
import cate.game.pvp.teampvp.dto.TeamPvpPlayerPsData;
import cate.game.pvp.teampvp.dto.TeamPvpReportData;
import cate.game.rank.po.Rank;
import cate.game.util.IntervalCounter;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@Slf4j
public class TeamPvpModule extends GroupModule<TeamPvpKv> {
    @Getter
    private final TeamPvpPoolModule pool = new TeamPvpPoolModule();
    @Getter
    private final TeamPvpTeamModule team = new TeamPvpTeamModule();
    @Getter
    private final TeamPvpInviteModule invite = new TeamPvpInviteModule();
    @Getter
    private final TeamPvpFightModule fight = new TeamPvpFightModule();

    private final TeamPvpRecvModule recv = new TeamPvpRecvModule();
    @Getter
    private final TeamPvpMsgModule msg = new TeamPvpMsgModule();

    public TeamPvpModule(GroupBody context) {
        super(context);
    }

    @Override
    protected GroupSubModule[] getSubModules() {
        return new GroupSubModule[]{pool, team, invite, fight, recv, msg};
    }

    @Override
    protected String getStatusKey() {
        return KvData.KEY_TEAM_PVP;
    }

    @Override
    public String getName() {
        return "组队竞技";
    }

    private IntervalCounter saveTrigger = new IntervalCounter(3600);

    @Override
    public void onInterval() {
        status.tick(this);
        fight.onInterval();
        pool.onInterval();
        if (saveTrigger.trigger()) {
            try{
                saveStatus();
                pool.savePlayers();
                team.saveTeams();
            } catch (Exception e) {
                log.error("组队竞技定时保存异常,e =", e);
            }
        }
    }

    public void updateRanks(List<Rank> ranks) {
        status.updateRankList(ranks);
    }

    public int getSeason() {
        return status.getSeason();
    }

    @Override
    protected int getIntervalSeconds() {
        return 1;
    }

    public List<TeamPvpPlayer> getInviteList(String leaderUid) {
        return pool.matchPowerList(leaderUid);
    }

    public GameResult<Void> invite(String leaderUid, String inviteUid) {
        GameResult<Void> r = new GameResult<>();
        GameResult<TeamPvpPlayer> poolRes = pool.invite(leaderUid, inviteUid);
        if (!poolRes.ok()) {
            return r.fail(poolRes);
        }
        r = team.invite(leaderUid, inviteUid);
        if (!r.ok()) {
            return r;
        }
        r = invite.addInvites(inviteUid, leaderUid);
        if (r.ok() && poolRes.data != null) {
            TeamPvpPlayer toNoticePlayer = poolRes.data;
            msg.sendRedPoint(toNoticePlayer.ps.snapshot.base.srvId, toNoticePlayer.ps.snapshot.uid);
        }
        return r;
    }

    public GameResult<TeamPvpTeam> answerInvite(boolean ok, String inviteUid, String leaderUid) {
        GameResult<TeamPvpTeam> r = new GameResult<>();
        if (ok) {
            GameResult<Void> agreeRes = pool.agreeInvite(inviteUid, leaderUid);
            if (!agreeRes.ok()) {
                return r.fail(agreeRes);
            }
            GameResult<TeamPvpTeam> teamRes = team.agreeInvite(leaderUid, inviteUid);
            if (!teamRes.ok()) {
                return r.fail(teamRes);
            }
            r.data = teamRes.data;
        }
        invite.answerInvite(inviteUid, leaderUid);
        return r;
    }

    public TeamPvpTeam syncTeamData(PlaySide ps, String abbr) {
        pool.updatePlayer(ps, abbr);
        TeamPvpTeam myTeam = team.findPlayerTeam(ps.snapshot.uid);
        if (myTeam == null) {
            myTeam = new TeamPvpTeam();
            myTeam.memberUids = Collections.singletonList(ps.snapshot.uid);
        }
        return myTeam;
    }

    public boolean hasInvitedList(String playerUid) {
        return CollectionUtils.isNotEmpty(invite.getInviteApplys(playerUid));
    }

    public List<TeamPvpPlayer> getInviteApplys(String inviteUid) {
        List<String> leaderUids = invite.getInviteApplys(inviteUid);
        return pool.findPlayersByUid(leaderUids);
    }

    public GameResult<TeamPvpTeam> changeLeader(String leaderUid, String newLeaderUid) {
        return team.changeLeader(leaderUid, newLeaderUid);
    }

    public GameResult<Void> kickOutTeam(String leaderUid, String toKickUid) {
        return team.kickOut(leaderUid, toKickUid);
    }

    public GameResult<TeamPvpMatchData> matchOpponent(String playerUid) {
        GameResult<TeamPvpMatchData> matchRes = new GameResult<>();
        TeamPvpTeam playerTeam = team.findPlayerTeam(playerUid);
        TeamPvpFightTask task = fight.findTask(playerTeam == null ? null : playerTeam.uid, playerUid);
        if (task != null) {
            if (!StringUtils.equals(task.challengerUid, playerUid) || task.isMatchOver()) {
                return matchRes.fail("您的队伍已经在战斗中，请稍后再试");
            }
            matchRes.data = taskToMatchData(task);
            return matchRes;
        }
        GameResult<List<TeamPvpPlayer>> matchOppoRes = pool.matchOpponent(playerTeam == null ? Collections.singletonList(playerUid) : playerTeam.memberUids);
        if (!matchOppoRes.ok()) {
            return matchRes.fail(matchOppoRes);
        }
        List<TeamPvpPlayer> aplayers = matchOppoRes.data.subList(0, 3);
        List<TeamPvpPlayer> bplayers = matchOppoRes.data.subList(3, 6);
        TeamPvpPlayer my = aplayers.stream().filter(e -> StringUtils.equals(e.ps.snapshot.uid, playerUid)).findAny().orElse(null);
        task = fight.addTask(
                playerUid,
                playerTeam == null ? playerUid : playerTeam.leaderUid,
                my == null ? 1000 : my.score,
                playerTeam == null ? (byte) 1 : 2,
                playerTeam == null ? null : playerTeam.uid,
                aplayers,
                bplayers);
        matchRes.data = taskToMatchData(task);
        return matchRes;
    }

    public GameResult<TeamPvpTeam> exitTeam(String playerUid) {
        return team.exitTeam(playerUid);
    }

    private List<TeamPvpPlayerPsData> transPlayerPsData(List<TeamPvpPlayer> players) {
        List<TeamPvpPlayerPsData> list = new ArrayList<>();
        for (TeamPvpPlayer player : players) {
            list.add(new TeamPvpPlayerPsData(
                    player.ps,
                    player.score,
                    player.power));
        }
        return list;
    }

    public GameResult<TeamPvpMatchData> updateFightPosition(String playerUid, List<String> newUids) {
        GameResult<TeamPvpMatchData> r = new GameResult<>();
        TeamPvpTeam playerTeam = team.findPlayerTeam(playerUid);
        GameResult<TeamPvpFightTask> updateRes = fight.updateTaskPos(playerUid, playerTeam == null ? null : playerTeam.uid, newUids);
        if (updateRes.ok()) {
            TeamPvpFightTask task = updateRes.data;
            r.data = taskToMatchData(task);
        }
        return r;
    }

    public TeamPvpMatchData savePosition(PlaySide ps, String abbr) {
        pool.updatePlayer(ps, abbr);
        TeamPvpTeam playerTeam = team.findPlayerTeam(ps.snapshot.uid);
        TeamPvpFightTask task = fight.savePosition(ps.snapshot.uid, playerTeam == null ? null : playerTeam.uid, ps);
        return taskToMatchData(task);
    }

    public GameResult<TeamPvpMatchData> matchRefresh(String playerUid) {
        GameResult<TeamPvpMatchData> refreshRes = new GameResult<>();
        TeamPvpTeam playerTeam = team.findPlayerTeam(playerUid);
        GameResult<Void> res = fight.canMatching(playerUid, playerTeam == null ? null : playerTeam.uid);
        if (!res.ok()) {
            return refreshRes.fail(res);
        }
        GameResult<List<TeamPvpPlayer>> matchOppoRes = pool.matchRefresh(playerTeam == null ? Collections.singletonList(playerUid) : playerTeam.memberUids);
        if (matchOppoRes.ok()) {
            List<TeamPvpPlayer> players = matchOppoRes.data;
            TeamPvpFightTask task = fight.refreshTask(playerTeam == null ? null : playerTeam.uid, playerUid, players.subList(0, 3), players.subList(3, 6));
            if (task != null) {
                refreshRes.data = taskToMatchData(task);
            }
        }
        return refreshRes;
    }

    private TeamPvpMatchData taskToMatchData(TeamPvpFightTask task) {
        if (task == null) {
            return null;
        }
        TeamPvpMatchData data = new TeamPvpMatchData();
        data.ateam = transPlayerPsData(task.ateam);
        data.bteam = transPlayerPsData(task.bteam);
        data.matchEndTime = task.matchEndTime;
        data.refreshTimes = task.refreshTimes;
        data.positionEndTime = task.positionEndTime;
        return data;
    }

    public TeamPvpMatchData aheadToPosition(String playerUid) {
        TeamPvpTeam playerTeam = team.findPlayerTeam(playerUid);
        TeamPvpFightTask task = fight.aheadToPosition(playerUid, playerTeam == null ? null : playerTeam.uid);
        return taskToMatchData(task);
    }

    public GameResult<Void> beginToFight(String playerUid) {
        TeamPvpTeam playerTeam = team.findPlayerTeam(playerUid);
        String teamUid = playerTeam == null ? null : playerTeam.uid;
        return fight.beginToFight(playerUid, teamUid);
    }

    public List<TeamPvpPlayer> findPlayers(List<String> playerUids) {
        return pool.findPlayersByUid(playerUids);
    }

    public void afterChallenge(TeamPvpReport report) {
        if (report == null || CollectionUtils.isEmpty(report.list)) {
            return;
        }
        for (String memberUid : report.memberUids) {
            TeamPvpPlayer player = pool.updatePlayer(memberUid, report.win ? report.score : - report.score);
            if (player != null) {
                msg.sendReport(player.ps.snapshot.base.srvId, new TeamPvpReportData(memberUid, report));
            }
        }
    }

    public TeamPvpPlayer searchPlayer(String name) {
        return pool.searchPlayer(name);
    }

    public List<Rank> loadRanks() {
        if (status.getPeriod() == TeamPvpKv.Period.SLEEP) {
            return status.loadRanks();
        } else {
            return pool.loadRanks();
        }
    }

    public List<Rank> loadGods() {
        if (status.getPeriod() == TeamPvpKv.Period.FIGHT) {
            return pool.loadGods();
        } else {
            return status.loadGods();
        }
    }

    public GameResult<Void> gmResetTimes(String playerUid) {
        return pool.gmResetTimes(playerUid);
    }
}
